﻿Imports System.IO
Imports System.Text
Imports System.ServiceModel.Web

Imports System.Net
Imports System.ServiceModel.Syndication
Imports Microsoft.DPE.Samples.SyndicationExtensions
Imports Microsoft.DPE.Samples.PictureProvider
Imports System.Web



''' <summary>
''' The InstanceContext can be any valid value. It is set to single to re-use the service object
''' </summary>
''' <remarks></remarks>
<ServiceBehavior(InstanceContextMode:=InstanceContextMode.Single)> _
Public Class PictureService
    Implements IPictureService






    ''' <summary>
    ''' Returns the service documentation
    ''' </summary>
    ''' <remarks>
    ''' /help
    ''' </remarks>
    Public Function GetDocumentation() As Stream Implements IPictureService.GetDocumentation
        Dim stream As New MemoryStream()

        Dim writer As New StreamWriter(stream, Encoding.UTF8)
        writer.Write(My.Resources.ServiceDoc)
        writer.Flush()

        stream.Position = 0

        WebOperationContext.Current.OutgoingResponse.ContentType = "text/html"
        Return stream
    End Function





    ''' <summary>
    ''' Returns the specified picture
    ''' </summary>
    ''' <remarks>
    ''' /picture/{pictureId}
    ''' </remarks>
    Public Function GetPicture(ByVal pictureId As String) As Stream Implements IPictureService.GetPicture

        Debug.WriteLine("GetPicture:  ID:" & pictureId)


        If (pictureId.LastIndexOf(".", StringComparison.Ordinal) < 0) Then

            WebOperationContext.Current.OutgoingResponse.SetStatusAsNotFound()
            Return Nothing
        End If


        Dim p = PictureManager.GetPictureById(pictureId)
        If p Is Nothing Then
            WebOperationContext.Current.OutgoingResponse.SetStatusAsNotFound()
            Return Nothing
        End If

        Dim stream As MemoryStream
        Using client As New WebClient

            Dim buffer = client.DownloadData(p.ItemUrl)
            stream = New MemoryStream(buffer)
        End Using

        ' Set MIME-type
        WebOperationContext.Current.OutgoingResponse.ContentType = p.MimeType
        Return stream
    End Function

    ''' <summary>
    ''' Returns a thumbnail of the specified picture
    ''' </summary>
    ''' <remarks>
    ''' /picture/t/{pictureId}
    ''' </remarks>       
    Public Function GetPictureThumbnail(ByVal pictureId As String) As Stream Implements IPictureService.GetPictureThumbnail
        If pictureId.LastIndexOf(".", StringComparison.Ordinal) < 0 Then

            WebOperationContext.Current.OutgoingResponse.SetStatusAsNotFound()
            Return Nothing
        End If


        Dim p = PictureManager.GetPictureById(pictureId)
        If p Is Nothing Then

            WebOperationContext.Current.OutgoingResponse.SetStatusAsNotFound()
            Return Nothing
        End If

        Dim path As String = IO.Path.Combine(IO.Path.GetTempPath(), Utils.CalculateMD5Hash(p.ItemUrl.ToString()))

        If Not File.Exists(path) Then
            Dim buffer As Byte()
            Using client As New WebClient()

                buffer = client.DownloadData(p.ItemUrl)
            End Using

            Dim image = Utils.ResizeImageFile(buffer, 300)
            File.WriteAllBytes(path, image)
        End If


        ' Set MIME-type
        WebOperationContext.Current.OutgoingResponse.ContentType = p.MimeType
        Return (New FileStream(path, FileMode.Open, FileAccess.Read))
    End Function






#Region "GetPictures"

    ''' <summary>
    ''' Returns a list of pictures in Atom 1.0
    ''' </summary>
    ''' <remarks>
    ''' /pictures/atom
    ''' </remarks>
    Public Function GetPicturesAsAtom() As System.ServiceModel.Syndication.Atom10FeedFormatter Implements IPictureService.GetPicturesAsAtom
        Dim feed = CreateFeed("Pictures", "All pictures")

        Dim list = PictureManager.GetPictures()

        feed.Items = ConvertPictureList(list.Take(PictureServiceSettings.DefaultFeedItemsCount))

        Return feed.GetAtom10Formatter()
    End Function


    ''' <summary>
    ''' Returns a list of pictures in RSS 2.0
    ''' </summary>
    ''' <remarks>
    ''' /pictures/rss
    ''' </remarks>
    Public Function GetPicturesAsRss() As System.ServiceModel.Syndication.Rss20FeedFormatter Implements IPictureService.GetPicturesAsRss
        Dim feed = CreateFeed("Pictures", "All pictures")

        Dim list = PictureManager.GetPictures()
        feed.Items = ConvertPictureList(list.Take(PictureServiceSettings.DefaultFeedItemsCount))

        Return feed.GetRss20Formatter(False)
    End Function





    ''' <summary>
    ''' Returns a list of pictures in the default format
    ''' </summary>
    ''' <remarks>
    ''' /pictures
    ''' </remarks>
    Public Function GetPicturesInDefaultFormat() As System.ServiceModel.Syndication.SyndicationFeedFormatter Implements IPictureService.GetPicturesInDefaultFormat
        Return GetPicturesAsRss()
    End Function

#End Region





    ''' <summary>
    ''' Returns a list of pictures that can be sorted and grouped
    ''' </summary>
    ''' <remarks>
    ''' /pictures/list
    ''' </remarks>
    Public Function GetPicturesListAsRss() As System.ServiceModel.Syndication.SyndicationFeedFormatter Implements IPictureService.GetPicturesListAsRss
        Dim feed = CreateFeed("Pictures List", "This is a sorted list of pictures")

        ' Add custom namespaces
        feed.DeclareNamespace("cf", ServiceUris.CFNamespace)
        feed.DeclareNamespace("psd", ServiceUris.PSDNamespace)

        ' add SLE elements to RSS Channel
        feed.AddSLEFeedExtensions()

        Dim list = PictureManager.GetPictures().Take(100).OrderBy(Function(i) (i.Title)).ToList()
        feed.Items = ConvertPictureList(list)

        ' add SLE extensions for each item
        feed.AddSLEItemExtensions(list)

        Dim Formatter = feed.GetRss20Formatter()

        Return Formatter
    End Function



#Region "GetPicturesByTag"

    '     public Atom10FeedFormatter GetPicturesByTagAsAtom(string tagName)
    '     {

    '     }

    ''' <remarks>
    ''' /pictures/tag/{tagName}/atom
    ''' </remarks>
    Public Function GetPicturesByTagAsAtom(ByVal tagName As String) As System.ServiceModel.Syndication.Atom10FeedFormatter Implements IPictureService.GetPicturesByTagAsAtom
        Dim feed = CreateFeed(String.Format("Pictures tagged {0}", tagName), _
                                      String.Format("This is a list of pictures tagged as '{0}'", tagName))

        Dim list = PictureManager.GetPicturesByTag(HttpUtility.UrlDecode(tagName))

        feed.Items = ConvertPictureList(list.Take(PictureServiceSettings.DefaultFeedItemsCount))

        Return feed.GetAtom10Formatter()
    End Function



    '     public Rss20FeedFormatter GetPicturesByTagAsRss(string tagName)
    '     {

    '     }

    ''' <remarks>
    ''' /pictures/tag/{tagName}/rss
    ''' </remarks>
    Public Function GetPicturesByTagAsRss(ByVal tagName As String) As System.ServiceModel.Syndication.Rss20FeedFormatter Implements IPictureService.GetPicturesByTagAsRss
        Dim feed = CreateFeed(String.Format("Pictures tagged {0}", tagName), _
                                                   String.Format("This is a list of pictures tagged as '{0}'", tagName))

        Dim list = PictureManager.GetPicturesByTag(HttpUtility.UrlDecode(tagName))

        feed.Items = ConvertPictureList(List.Take(PictureServiceSettings.DefaultFeedItemsCount))

        Return feed.GetRss20Formatter(False)
    End Function


  


    ''' <remarks>
    ''' /pictures/tag/{tagName}
    ''' </remarks>
    Public Function GetPicturesByTagInDefaultFormat(ByVal tagName As String) As System.ServiceModel.Syndication.SyndicationFeedFormatter Implements IPictureService.GetPicturesByTagInDefaultFormat
        Return GetPicturesByTagAsRss(tagName)
    End Function


#End Region


    Private Shared Function CreateFeed(ByVal title As String, ByVal description As String) As SyndicationFeed
        Dim feed As New SyndicationFeed()

        With feed
            .Title = New TextSyndicationContent(title)
            .Description = New TextSyndicationContent(description)
            .Generator = "Picture Services"
            .Copyright = New TextSyndicationContent(PictureServiceSettings.Copyright)
            .Authors.Add(New SyndicationPerson(PictureServiceSettings.AuthorEmail, PictureServiceSettings.AuthorName, String.Empty))
            .Language = "en-us"
            .LastUpdatedTime = DateTime.Now
        End With

        Return feed
    End Function




    Private Shared Function ConvertPictureList(ByVal picturelist As IEnumerable(Of Picture)) As IEnumerable(Of SyndicationItem)
        Dim items As New List(Of SyndicationItem)

        For Each p In picturelist



            Dim item As New SyndicationItem()

            item.Title = New TextSyndicationContent(p.FileName)
            item.Copyright = New TextSyndicationContent(PictureServiceSettings.Copyright)
            item.Authors.Add(New SyndicationPerson(PictureServiceSettings.AuthorEmail, PictureServiceSettings.AuthorName, String.Empty))
            item.PublishDate = p.DateCreated
            item.LastUpdatedTime = p.DateModified

            ' add tags as categories
            For Each tag In p.Tags
                item.Categories.Add(New SyndicationCategory(tag))
            Next

            Dim pictureUri = BuildPictureUri(ServiceUris.GetPicture, p)
            Dim pictureThumbUri = BuildPictureUri(ServiceUris.GetPictureThumbnail, p)

            item.Id = pictureUri.ToString()
            item.Links.Add(New SyndicationLink(pictureUri, "enclosure", p.Title, p.MimeType, p.Size))
            item.Links.Add(New SyndicationLink(pictureUri))

            Dim html As New StringBuilder()
            html.AppendFormat("<p><a href=""{0}""><img src=""{1}"" border=""0"" alt=""{2}"" /></a></p>", pictureUri, pictureThumbUri, p.Title)

            If Not String.IsNullOrEmpty(p.Title) Then
                html.AppendFormat("<b>{0}</b><br />", p.Title)

                If Not String.IsNullOrEmpty(p.Comment) Then html.AppendFormat("{0}", p.Comment)

                html.AppendFormat("<p>Rating: <b>{0}</b></p>", p.RatingText)
                item.Content = SyndicationContent.CreateHtmlContent(html.ToString())

                items.Add(item)
            End If
        Next
        Return items
    End Function




    Private Shared Function BuildPictureUri(ByVal localUri As String, ByVal p As Picture) As Uri
        Dim baseUri = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.BaseUri
        Dim pictureUT = New UriTemplate(localUri)
        Dim pictureUri = pictureUT.BindByPosition(baseUri, p.Id + p.FileExtension)
        Return New Uri(HttpUtility.UrlDecode(pictureUri.ToString))
    End Function




    Private Sub SetCaching(ByVal context As WebOperationContext, ByVal lastModifiedDate As DateTime, ByVal maxCacheAge As Int32)
        ' set CacheControl header
        Dim cacheHeader = HttpResponseHeader.CacheControl
        Dim cacheControlValue = String.Format("max-age={0}, must-revalidate", maxCacheAge)
        context.OutgoingResponse.Headers.Add(cacheHeader, cacheControlValue)

        ' set cache validation 
        context.OutgoingResponse.LastModified = lastModifiedDate
        Dim eTag = context.IncomingRequest.UriTemplateMatch.RequestUri.ToString() + lastModifiedDate.ToString()
        context.OutgoingResponse.ETag = eTag
    End Sub







End Class
